package net.zoneland.knowledge.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import com.branchitech.account.command.GetUsersInCompanyByUserNameCommand;
import com.branchitech.account.ldap.Department;
import com.branchitech.account.ldap.UserBean;
import com.branchitech.gum.domain.Organization;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;

import net.zoneland.knowledge.enums.CmpDnEnum;
import net.zoneland.knowledge.enums.QaBankCmpDnEnum;
import net.zoneland.knowledge.exceptions.UserServiceException;
import net.zoneland.knowledge.model.LoginUserPojo;

/**
 * Uom实现.
 *
 * @author: bcc
 *     2022/3/11
 */
@ConditionalOnProperty(name = "biz.user-service", havingValue = "uom")
@Service
public class UserServiceServiceUom extends AbstractUserService{

    /**
     * guava缓存，获取内存.
     */
    private static final Cache<String, List<Organization>> cache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build();

    private static final String CATCH_NAME = "CATCH_NAME";

    @Override
    public LoginUserPojo getUserByUid(final String uid) {
        final LoginUserPojo user = new LoginUserPojo();
        final UserBean userBean = UserBean.getInstanceByID(uid);
        BeanUtils.copyProperties(userBean, user);
        return user;
    }

    @Override
    public String getCityId(final LoginUserPojo user) {
        return CmpDnEnum.getCityByValue(user.getCompanyDN());
    }

    @Override
    public List<Organization> queryBranchCompList(boolean includeCommon) throws UserServiceException {
        try {
            return cache.get(CATCH_NAME + includeCommon, () -> Arrays.stream(QaBankCmpDnEnum.values())
                    .filter(item -> includeCommon || item != QaBankCmpDnEnum.COMMON)
                    .map(this::transferCmpDnEnumToOrganization)
                    .collect(Collectors.toList()));
        } catch (ExecutionException e) {
            throw new UserServiceException("getUserByUid error includeCommon:" + includeCommon, e);
        }
    }

    @Override
    public List<Organization> queryDeptByCompCode(final String companyCode) {

        return Optional.ofNullable(companyCode)
                .map(Department::getInstance)
                .map(Department::getSubDepts)
                .map(List::stream)
                .orElseGet(Stream::empty)
                .map(this::transferDepartmentToOrganization)
                .collect(Collectors.toList());

    }

    @Override
    public boolean checkUserExists(final String userName, final String orgCode) throws UserServiceException {
        //全省通用的情况没法验证
        if (QaBankCmpDnEnum.COMMON.getValue().equals(orgCode)) {
            return true;
        }
        final String[] targetUsers = userName.split("、|/");
        for (int i = 0; i < targetUsers.length; i++) {
            UserBean[] users = (new GetUsersInCompanyByUserNameCommand(targetUsers[i], orgCode, null)).execute();
            if (users.length > 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<String> getUserDeptCodeAndParentDeptCode(final LoginUserPojo loginUserPojo) throws UserServiceException {
        final List<String> deptDns =  Lists.newArrayList(loginUserPojo.getDepartmentDN());
        Department instance = Department.getInstance(loginUserPojo.getDepartmentDN());
        while (instance != null) {
            instance = Department.getInstance(instance.getParentOrgDn());
            if (null != instance) {
                deptDns.add(instance.getDn());
            }
        }
        return deptDns;
    }

    private Organization transferCmpDnEnumToOrganization(final QaBankCmpDnEnum company) {
        final Organization o = new Organization();
        o.setOrgCode(company.getValue());
        o.setOrgName(company.getName());
        return o;
    }

    private Organization transferDepartmentToOrganization(final Department department) {
        final Organization o = new Organization();
        o.setOrgCode(department.getDn());
        o.setOrgName(department.getCnName());
        return o;
    }

}
